﻿#define USE_BARTENDER

#if USE_BARTENDER
using Seagull.BarTender.Print;
#endif

using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using UniRlv.COL;
using UniRlv.Utility.AppLib;
using UniRlv.Utility.Extend;

namespace UniRlv.Utility
{
    public class WorkSpace
    {
        private static WorkSpace _instance = null;
        //TcpChannel channel = null;
        public List<ScannerDevice> scanners = new List<ScannerDevice>();
        public List<PrintInfo> printerInfos;//打印信息
        public List<List<string>> printDatas = new List<List<string>>();//打印数据
        public DODevice doDev = null;
        private List<LineDevice> devs;
        public EventHandler<CodeSaveEventArg> CodeSaveEvent;
        public EventHandler<CodeScanEventArg> CodeScanEvent;//工控扫描枪扫码时触发
        public EventHandler<CodeEditEventArg> CodeEditEvent;//工控扫描枪编辑数据时触发
        public EventHandler<EventArgs> CodeRefreshEvent;//异常处理时触发
        public EventHandler<CodePrintEventArg> CodePrintEvent;//打印触发
        public EventHandler<EventArgs> TaskStartEvent;
        public EventHandler<EventArgs> TaskFinishEvent;
        public EventHandler<EventArgs> TaskResumeEvent;
        public EventHandler<EventArgs> TaskPauseEvent;
        public EventHandler<EventArgs> CriticalErrorEvent;

        public string StartupPath;
        int nMaunalScanner = 0;
        int nPrintLackQty = 50;
        public bool bVoiceTip = false;
        public bool bVoiceTipLevel1 = false;
        public bool bPickBind = false;
        bool bInit = false;
        object objPrint = new object();

        // private string _errorString;
        private Queue<string> liStrings = new Queue<string>();

        public bool IfHasInit
        {
            get
            {
                return bInit;
            }
        }
        public string ErrorString
        {
            get
            {
                //if (string.IsNullOrEmpty(_errorString))
                //{
                //    return "";
                //}
                //else
                //{
                //    string buf = new string(_errorString.ToCharArray());
                //    ErrorString = string.Empty;
                //    return buf;
                //}
                if (liStrings.Count > 0)
                {
                    return liStrings.Dequeue();
                }
                return "";

            }
            set
            {
                liStrings.Enqueue(value);
            }
        }

#if USE_BARTENDER
        Engine engine = null; // The BarTender Print Engine
#endif


        public static WorkSpace GetInstance()
        {
            //return Singleton<WorkSpace>.GetInstance();

            if (_instance == null)
            {
                _instance = new WorkSpace();
            }

            return _instance;
        }

        public bool Init(string serverIP, ref string msg)
        {
            //客户端注册服务端事件
            if (bInit)
            {
                return true;
            }
            try
            {
                //BinaryServerFormatterSinkProvider serverProvider = new BinaryServerFormatterSinkProvider();

                //serverProvider.TypeFilterLevel = TypeFilterLevel.Full;

                //IDictionary dict = new Hashtable();

                //dict["port"] = 0;
                //dict["name"] = "UniRlvChanel";
                //dict["timeout"] = 30000;

                //if (!string.IsNullOrEmpty(ConfigurationHelper.AppGetString("localIP")))
                //{
                //    dict["bindTo"] = ConfigurationHelper.AppGetString("localIP");
                //}
                //else//取最后一个ip
                //{
                //    dict["bindTo"] = NetHelper.GetLocalIp(true);
                //}

                //if (channel != null)
                //{
                //    ChannelServices.UnregisterChannel(channel);
                //}

                //PublicObject.BindingIP = dict["bindTo"].ToString();

                //channel = new TcpChannel(dict,
                //    new BinaryClientFormatterSinkProvider(), serverProvider);

                //ChannelServices.RegisterChannel(channel, false);
                //PublicObject.srv = (IServerOpr)(Activator.GetObject(typeof(IServerOpr),
                //        string.Format("tcp://{0}:{1}/UniRlvSolu/UniRlv", serverIP, ConfigurationHelper.AppGetInt("port"))));

                #region 数据库结构更新

                if (!DALOpr.IfColumnExist("PackageRule", "minTagGG"))
                {
                    msg = string.Empty;

                    if (!DALOpr.AddColumn("PackageRule", "minTagGG", "varchar(50) NULL", ref msg))
                    {
                        msg = "PackageRule表无法添加minTagGG列";
                        return false;
                    }
                }

                if (DALOpr.IfTableExist("PrintInfo"))
                {
                    Console.WriteLine("PrintInfo table exist!");
                }
                else
                {
                    Console.WriteLine("PrintInfo table no exist!");
                    string sql = "CREATE TABLE [dbo].[PrintInfo]([id] [int] IDENTITY(1,1) NOT NULL,[taskID] [int] NOT NULL,[stationNum] [int] NOT NULL,[subDeviceNum] [int] NULL,[name] [nvarchar](50) NOT NULL,[initString] [nvarchar](200) NULL,[templatePath] [nvarchar](500) NOT NULL,[codePath] [nvarchar](500) NOT NULL,[printWord] [int] NULL,[printQty] [int] NOT NULL,CONSTRAINT [PK_PrintInfo] PRIMARY KEY CLUSTERED ([id] ASC)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]) ON [PRIMARY]";


                    if(!DALOpr.ExecuteNonQuery(sql, ref msg))
                    {
                        return false;
                    }
                }

                if (DALOpr.IfTableExist("PrintCode"))
                {
                    Console.WriteLine("PrintCode table exist!");
                }
                else
                {
                    Console.WriteLine("PrintCode no exist!");
                    string sql = "CREATE TABLE [dbo].[PrintCode]([ID] [int] IDENTITY(1,1) NOT NULL ,[code] [nvarchar](1024) NOT NULL,[PrintInfoID] [int] NOT NULL,PRIMARY KEY ([id]))";

                    if(!DALOpr.ExecuteNonQuery(sql, ref msg))
                    {
                        return false;
                    }
                }
                

                if (!DALOpr.IfColumnExist("ProductionTask", "minTagGG"))
                {
                    msg = string.Empty;

                    if (!DALOpr.AddColumn("ProductionTask", "minTagGG", "varchar(50) NULL", ref msg))
                    {
                        msg = "ProductionTask表无法添加minTagGG列";
                        return false;
                    }
                }


                if (!DALOpr.IfColumnExistArchieve("ProductionTask", "minTagGG"))
                {
                    Console.WriteLine("UniRlv_Archieve minTagGG column no exist!");

                    if (!DALOpr.AddColumnArchieve("ProductionTask", "minTagGG", "varchar(50)", ref msg))
                    {
                        return false;
                    }
                }

                if (!DALOpr.IfColumnExist("ProductionTask", "spm"))
                {
                    Console.WriteLine("spm column no exist!");

                    if(!DALOpr.AddColumn("ProductionTask", "spm", "varchar(100)", ref msg))
                    {
                        return false;
                    }
                }

                if (!DALOpr.IfColumnExistArchieve("ProductionTask", "spm"))
                {
                    Console.WriteLine("UniRlv_Archieve spm column no exist!");

                    if (!DALOpr.AddColumnArchieve("ProductionTask", "spm", "varchar(100)", ref msg))
                    {
                        return false;
                    }
                }

                if (!DALOpr.IfColumnExist("ProductionTask", "operateDate"))
                {
                    Console.WriteLine("operateDate column no exist!");

                    if (!DALOpr.AddColumn("ProductionTask", "operateDate", "datetime DEFAULT (getdate())", ref msg))
                    {
                        return false;
                    }
                }

                if (!DALOpr.IfColumnExistArchieve("ProductionTask", "operateDate"))
                {
                    Console.WriteLine("UniRlv_Archieve operateDate column no exist!");

                    if (!DALOpr.AddColumnArchieve("ProductionTask", "operateDate", "datetime DEFAULT (getdate())", ref msg))
                    {
                        return false;
                    }
                }

                if (!DALOpr.IfColumnExist("ProductionTask", "extendInfo"))
                {
                    Console.WriteLine("extendInfo column no exist!");

                    if (!DALOpr.AddColumn("ProductionTask", "extendInfo", "varchar(200)", ref msg))
                    {
                        return false;
                    }
                }

                if (!DALOpr.IfColumnExistArchieve("ProductionTask", "extendInfo"))
                {
                    Console.WriteLine("UniRlv_Archieve extendInfo column no exist!");

                    if (!DALOpr.AddColumnArchieve("ProductionTask", "extendInfo", "varchar(200)", ref msg))
                    {
                        return false;
                    }
                }

                if (!DALOpr.IfColumnExist("CompanyInfo", "phone"))
                {
                    Console.WriteLine("phone column no exist!");

                    if(!DALOpr.AddColumn("CompanyInfo", "phone", "varchar(20)", ref msg))
                    {
                        return false;
                    }
                }

                if (!DALOpr.IfColumnExist("PrintInfo", "SrcID"))
                {
                    Console.WriteLine("SrcID column no exist!");

                    if (!DALOpr.AddColumn("PrintInfo", "SrcID", "int", ref msg))
                    {
                        return false;
                    }
                }

                BkDB();

                #endregion

                PublicObject.arrCode1 = new MyList<CodeInfo>();
                PublicObject.arrCode2 = new List<CodeInfo>(50000);
                PublicObject.arrCode3 = new List<CodeInfo>(10000);
                PublicObject.arrCode4 = new List<CodeInfo>(5000);
                PublicObject.arrCode1.bMergeOne = false;

                int qty = ConfigurationHelper.AppGetInt("checkDataQty");
                qty = qty <= 0 ? 50 : qty;

                PublicObject.CodeScanned = new List<string>();
                PublicObject.CodeValid = new List<string>();
                PublicObject.CodeRlt = new List<CodeRltInfo>();

                List<CompanyInfo> li = DALOpr.QueryAll<CompanyInfo>(ref msg);

                if (li == null || li.Count == 0)
                {
                    //插入默认元素
                    CompanyInfo info = new CompanyInfo();
                    info.ID = DALOpr.GetNextObjectID("CompanyInfo");
                    info.name = "xxx公司";
                    info.userName = "xxx操作员";

                    msg = string.Empty;
                    if (DALOpr.Insert(info, ref msg))
                    {
                        PublicObject.CurCompany = info;
                    }
                    else
                    {
                        msg = "无法插入默认企业信息";
                        return false;
                    }
                }
                else
                {
                    //显示第一个元素
                    PublicObject.CurCompany = li[0];
                }


                //初始化工控扫描枪
                List<LineDevice> infos = DALOpr.Query<LineDevice>("IO=" + (int)input_output.INPUT + " and deviceType=" + (int)in_device_type.IDT_MANUAL_SCANER, ref msg);

                if (infos.Count>0)
                {
                    ScannerDevice sd = new ScannerDevice(infos[0]);
                    sd.OnCode += sd_OnCode;

                    if (sd.Open())
                    {
                        scanners.Add(sd);
                        nMaunalScanner = 1;
                    }
                    else
                    {
                        //msg = "工控扫描枪打开失败";
                        //return false;//会导致无法进入主界面重新配置扫描枪信息
                    }
                }

                CodePrcUtility.PRODUCT_CHECK = ConfigurationHelper.AppGetBoolean("checkProduct");
                CodePrcUtility.PRODUCT_CHECKLevel1 = ConfigurationHelper.AppGetBoolean("checkProductLevel1");
                CodePrcUtility.CODEREG = ConfigurationHelper.AppGetString("codeReg");
                nPrintLackQty = ConfigurationHelper.AppGetInt("printLackQty");

                if (nPrintLackQty<=0)
                {
                    nPrintLackQty = 50;
                }
                bVoiceTip = ConfigurationHelper.AppGetBoolean("voiceTip");
                bVoiceTipLevel1 = ConfigurationHelper.AppGetBoolean("voiceTipLevel1");
                bPickBind = ConfigurationHelper.AppGetBoolean("pickBingding");

                InputDataPrc.GetInstance().Init(this);

                bInit = true;
            }
            catch (Exception ex)
            {
                msg = ex.Message;
                return false;
            }

            return true;
        }

        private void BkDB()
        {
            int days = ConfigurationHelper.AppGetInt("dbBKPeriod");

            ThreadPool.QueueUserWorkItem(new WaitCallback((s=> 
            {
                int d = Convert.ToInt32(s);

                if (d<=0)
                {
                    d = 90;
                }
                string msg = string.Empty;
                DALOpr.BkDB(d, ref msg);

            })), days);
        }

        public bool Quit()
        {
            //if (channel != null)
            //{
            //    ChannelServices.UnregisterChannel(channel);
            //}
            if(!InputDataPrc.GetInstance().Quit())
            {
                ErrorString = InputDataPrc.GetInstance().ErrorString;
                return false;
            }

            foreach (var item in scanners)
            {
                item.Close();
            }

            if (doDev!=null)
            {
                doDev.Close();
            }

            if (PublicObject.CurTask != null)
            {
                ProductionTask t = PublicObject.CurTask;
                t.state = (int)task_state.TS_STOP;
                //t.scanQuantity = PublicObject.arrCode1.Count;//审核任务后才更新任务的扫码数量
                
                string sql = EntityHelper.GetUpdateSql(PublicObject.CurTask);
                string msg = string.Empty;

                DALOpr.ExecuteNonQuery(sql, ref msg);

                //删除打印信息，回写未打印数据
                if (printerInfos != null)
                {
                    for (int i = 0; i < printDatas.Count; i++)
                    {
                        //2021-7-27改为回写数据库
                        //if (File.Exists(printerInfos[i].CodePath))
                        //    File.WriteAllLines(printerInfos[i].CodePath, printDatas[i], FileUtil.GetEncoding(printerInfos[i].CodePath));


                        msg = string.Empty;
                        sql = "delete from PrintCode where PrintInfoID = " + printerInfos[i].SrcID;

                        DALOpr.ExecuteNonQuery(sql, ref msg);

                        //插入码明细
                        DataTable dt = new DataTable();
                        dt.Columns.Add("code", typeof(string));
                        dt.Columns.Add("PrintInfoID", typeof(int));

                        foreach (var item in printDatas[i])
                        {
                            DataRow dr = dt.NewRow();
                            dr[0] = item;
                            dr[1] = printerInfos[i].SrcID;

                            dt.Rows.Add(dr);
                        }

                        DALOpr.ExcuteBulkCopy("PrintCode", dt, ref msg);
                    }
                    printerInfos.Clear();
                    printDatas.Clear();
                }
            }

            return true;
        }

        #region 关于任务
        #region 数据库备份


        #endregion
        public bool RunTask()
        {
            //输入设备
            string msg = string.Empty;

            PublicObject.arrCode1.bMergeOne = false;
            PublicObject.bSecond = false;
            PublicObject.CurTask.exportTimes = 0;//导出次数清零
            PublicObject.CurTask.verifyer = "";

            //重新加载配置，这样重启任务可以是配置生效 2020-12-24
            CodePrcUtility.PRODUCT_CHECK = ConfigurationHelper.AppGetBoolean("checkProduct");
            CodePrcUtility.PRODUCT_CHECKLevel1 = ConfigurationHelper.AppGetBoolean("checkProductLevel1");
            CodePrcUtility.CODEREG = ConfigurationHelper.AppGetString("codeReg");
            nPrintLackQty = ConfigurationHelper.AppGetInt("printLackQty");

            if (nPrintLackQty <= 0)
            {
                nPrintLackQty = 50;
            }
            bVoiceTip = ConfigurationHelper.AppGetBoolean("voiceTip");
            bVoiceTipLevel1 = ConfigurationHelper.AppGetBoolean("voiceTipLevel1");
            bPickBind = ConfigurationHelper.AppGetBoolean("pickBingding");

            devs = DALOpr.Query<LineDevice>("stationNumber>0 and lineID=" + PublicObject.CurLine.ID, ref msg);

            ScannerDevice sd;
            bool bOK = true;

            string sql = EntityHelper.GetQuerySql<ProductInfo>();
            ProductInfo productInfo = DALOpr.QuerySingle<ProductInfo>(sql + " where ID=" + PublicObject.CurTask.productID, ref msg);

            if (productInfo == null)
            {
                PublicObject.CurProduct = new ProductInfo();
                PublicObject.CurProduct.company = PublicObject.CurTask.company;
                PublicObject.CurProduct.createTime = DateTime.Now;
                PublicObject.CurProduct.creator = PublicObject.CurUser.name;
                PublicObject.CurProduct.gg = PublicObject.CurTask.gg;
                PublicObject.CurProduct.itemid = PublicObject.CurTask.number;
                PublicObject.CurProduct.pzrq = DateTime.Now;
                PublicObject.CurProduct.pzwh = PublicObject.CurTask.pzwh;
                PublicObject.CurProduct.spm = PublicObject.CurTask.spm;
                PublicObject.CurProduct.state = 1;
                PublicObject.CurProduct.tym = PublicObject.CurTask.tym;
            }
            else
            {
                PublicObject.CurProduct = productInfo;
            }
            


            foreach (var item in devs)
            {
                if (item.IO == (int)input_output.INPUT && (item.deviceType == (int)in_device_type.IDT_AUTO_SCANER
                    || item.deviceType == (int)in_device_type.IDT_OTHERS || item.deviceType == (int)in_device_type.IDT_OCR_CAMERA))
                {
                    sd = new ScannerDevice(item);
                    sd.OnCode += sd_OnCode;

                    bOK &= sd.Open();

                    if (!bOK)
                    {
                        ErrorString = sd.ErrorString;
                        break;
                    }
                    else
                    {
                        scanners.Add(sd);

                        if (item.twiceScan == 1)
                        {
                            PublicObject.bSecond = true;
                        }

                        if (item.subDeviceNumber > 0 && item.stationNumber == 1)
                        {//1号工位有子设备，说明多台设备同时读取一级码
                            PublicObject.arrCode1.bMergeOne = true;
                        }
                    }
                }

                if (item.IO == (int)input_output.OUTPUT &&
                    (item.deviceType == (int)out_device_type.ODT_PLC
                    || item.deviceType == (int)out_device_type.ODT_RELAY
                    || item.deviceType == (int)out_device_type.ODT_OTHERS))
                {
                    doDev = new DODevice(item);
                    bOK &= doDev.Open();

                    if (!bOK)
                    {
                        ErrorString = doDev.ErrorString;
                        break;
                    }
                }

                //综合扫描枪或功能扫描枪
                if (item.IO == (int)input_output.INPUT && (item.deviceType == (int)in_device_type.IDT_FUNC_SCANNER ||
                    item.deviceType == (int)in_device_type.IDT_UNI_SCANER))
                {

                    sd = new ScannerDevice(item);
                    sd.OnCode += sd_OnCode;

                    bOK &= sd.Open();

                    if (!bOK)
                    {
                        ErrorString = sd.ErrorString;
                        break;
                    }
                    else
                    {
                        scanners.Add(sd);
                        CodePrcUtility.AddUniScanner(item);
                    }

                }

                //工控扫描枪
                if (item.IO == (int)input_output.INPUT && item.deviceType == (int)in_device_type.IDT_MANUAL_SCANER && nMaunalScanner == 0)
                {

                    sd = new ScannerDevice(item);
                    sd.OnCode += sd_OnCode;

                    bOK &= sd.Open();

                    if (!bOK)
                    {
                        ErrorString = sd.ErrorString;
                        break;
                    }
                    else
                    {
                        scanners.Add(sd);
                        nMaunalScanner = 1;
                    }

                }

            }

            if (bOK)
            {
                //打印信息
                printerInfos = DALOpr.Query<PrintInfo>("taskID=" + PublicObject.CurTask.ID, ref msg);
                if (printerInfos != null && printerInfos.Count > 0)
                {
                    PublicObject.bPrint = true;

                    foreach (var pi in printerInfos)
                    {
                        //2021-7-27 改为从数据库加载打印数据

                        //List<string> datas = null;

                        //if (File.Exists(pi.CodePath))
                        //{
                        //    datas = File.ReadAllLines(pi.CodePath, FileUtil.GetEncoding(pi.CodePath)).ToList();

                        //    //显示警告信息与启动任务的进度条冲突
                        //    if (datas.Count < nPrintLackQty)
                        //    {
                        //        ErrorString = string.Format("{0}号工位待打印数据已不足{1}条，剩余{2}条", pi.StationNum, nPrintLackQty, datas.Count);
                        //        CriticalErrorEvent(this, new EventArgs());
                        //    }
                        //}
                        //else
                        //{
                        //    datas = new List<string>();

                        //    ErrorString = string.Format("{0}号工位待打印数据文件不存在", pi.StationNum);
                        //    CriticalErrorEvent(this, new EventArgs());
                        //}

                        List<PrintCode> codes = DALOpr.Query<PrintCode>("PrintInfoID=" + pi.SrcID, ref msg);

                        if (codes.Count< nPrintLackQty)
                        {
                            ErrorString = string.Format("{0}号工位待打印数据已不足{1}条，剩余{2}条", pi.StationNum, nPrintLackQty, codes.Count);
                            CriticalErrorEvent(this, new EventArgs());
                        }

                        printDatas.Add(codes.ConvertAll(s=>s.code));

                    }

#if USE_BARTENDER
                if (engine == null)
                {
                    engine = new Engine(true);
                }
#endif
                }
            }


            if (!bOK)
            {
                for (int i = scanners.Count - 1; i >= 0; i--)
                {
                    var item = scanners[i];

                    if (item.Device.IO == (int)input_output.INPUT && item.Device.deviceType == (int)in_device_type.IDT_MANUAL_SCANER)
                    {//工控扫描枪不关闭
                        continue;
                    }

                    item.Close();
                    scanners.RemoveAt(i);
                }
            }
            else
            {
                if (TaskStartEvent != null)
                {
                    TaskStartEvent(this, new EventArgs());
                }

                PublicObject.CurTask.state = (int)task_state.TS_RUN;
            }

            //清空临时日志信息
            for (int i = 1; i <= 4; i++)
            {
                string fileTmp = string.Format("{0}\\log\\{1}_{2}.log", StartupPath, i, PublicObject.CurTask.ID);
                if (File.Exists(fileTmp))
                {
                    File.Delete(fileTmp);
                }
            }

            return bOK;
        }

        public void PauseTask()
        {
            foreach (var item in scanners)
            {
                if (item.Device.IO == (int)input_output.INPUT && item.Device.deviceType == (int)in_device_type.IDT_MANUAL_SCANER)
                {//工控扫描枪不暂停
                    continue;
                }
                item.Pause();
            }

            PublicObject.CurTask.state = (int)task_state.TS_PAUSE;

            if (TaskPauseEvent != null)
            {
                TaskPauseEvent(this, new EventArgs());
            }
        }

        public void ResumeTask()
        {
            foreach (var item in scanners)
            {
                if (item.Device.IO == (int)input_output.INPUT && item.Device.deviceType == (int)in_device_type.IDT_MANUAL_SCANER)
                {
                    continue;
                }

                item.Resume();
            }

            PublicObject.CurTask.state = (int)task_state.TS_RUN;

            if (TaskResumeEvent != null)
            {
                TaskResumeEvent(this, new EventArgs());
            }
        }

        public void ReStartTask()
        {
            //清除缓存数据
            foreach (var item in PublicObject.arrCode1)
            {
                PublicObject.CodeScanned.Remove(item.code);
            }

            foreach (var item in PublicObject.arrCode2)
            {
                PublicObject.CodeScanned.Remove(item.code);
            }

            foreach (var item in PublicObject.arrCode3)
            {
                PublicObject.CodeScanned.Remove(item.code);
            }

            foreach (var item in PublicObject.arrCode4)
            {
                PublicObject.CodeScanned.Remove(item.code);
            }

            PublicObject.arrCode1.Clear();
            PublicObject.arrCode2.Clear();
            PublicObject.arrCode3.Clear();
            PublicObject.arrCode4.Clear();


            //PublicObject.CodeScanned.Clear();//不能清空，不然重启任务之后不能历史查重
            //PublicObject.CodeValid.Clear();//不能清空，不然重启任务之后不能使用数据源查重
            //PublicObject.CodeRlt.Clear();

            PublicObject.Picks1 = 0;
            PublicObject.Picks2 = 0;
            PublicObject.Picks3 = 0;
            PublicObject.TopMan = 0;
            PublicObject.TopLoss = 0;

            if (TaskStartEvent!=null)
            {
                TaskStartEvent(this, new EventArgs());
            }

            RefreshCodeQty();
        }

        public void FinishTask(task_state ts, ref string strMsg)
        {
            //保存任务、码信息
            if (ts == task_state.TS_VERIFIED)
            {
                PublicObject.CurTask.scanQuantity = PublicObject.arrCode1.Count;
                PublicObject.CurTask.packageState = (int)GetCurrentTaskPS();


                //回写查重数据
                if (File.Exists(PublicObject.CurTask.extendInfo))
                {
                    //移除已扫描数据
                    for (int i = PublicObject.CodeValid.Count - 1; i >= 0; i--)
                    {
                        string code24Bit = AppHelper.SYZSGet24BitFromCodeNoCheck(PublicObject.CodeValid[i]);
                        if (CodePrcUtility.CheckDuplicate(code24Bit))
                        {
                            PublicObject.CodeValid.RemoveAt(i);
                        }
                    }
                    File.WriteAllLines(PublicObject.CurTask.extendInfo, PublicObject.CodeValid, Encoding.UTF8);
                }

            }


            PublicObject.CurTask.state = (int)ts;
            string sql = EntityHelper.GetUpdateSql(PublicObject.CurTask);
            string msg = string.Empty;

            DALOpr.ExecuteNonQuery(sql, ref msg);

            //清空临时日志信息
            for (int i = 1; i <= 4; i++)
            {
                string fileTmp = string.Format("{0}\\tmp\\{1}_{2}.log", StartupPath, i, PublicObject.CurTask.ID);
                if (File.Exists(fileTmp))
                {
                    File.Delete(fileTmp);
                }
            }

            //设置为空任务，以启动下一任务
            PublicObject.CurTask = null;

            PublicObject.arrCode1.Clear();
            PublicObject.arrCode2.Clear();
            PublicObject.arrCode3.Clear();
            PublicObject.arrCode4.Clear();

            PublicObject.CodeScanned.Clear();
            PublicObject.CodeValid.Clear();
            PublicObject.CodeRlt.Clear();

            PublicObject.Picks1 = 0;
            PublicObject.Picks2 = 0;
            PublicObject.Picks3 = 0;
            PublicObject.TopMan = 0;
            PublicObject.TopLoss = 0;

            for (int i = scanners.Count-1; i>=0; i--)
            {
                var item = scanners[i];

                if (item.Device.IO == (int)input_output.INPUT && item.Device.deviceType == (int)in_device_type.IDT_MANUAL_SCANER)
                {//工控扫描枪不关闭
                    continue;
                }

                item.Close();
                scanners.RemoveAt(i);
            }

            if (doDev!=null)
            {
                doDev.Close();
            }

	        //删除综合采集器
            CodePrcUtility.ClearUniScanner();

            if (TaskFinishEvent != null)
            {
                TaskFinishEvent(this, new EventArgs());
            }

            //删除打印信息，回写未打印数据
            if (printerInfos!=null)
            {
                for (int i = 0; i < printerInfos.Count; i++)
                {
                    //2021-7-27改为回写数据库
                    //if (File.Exists(printerInfos[i].CodePath))
                    //{
                    //    File.WriteAllLines(printerInfos[i].CodePath, printDatas[i], FileUtil.GetEncoding(printerInfos[i].CodePath));
                    //}

                    msg = string.Empty;
                    sql = "delete from PrintCode where PrintInfoID = " + printerInfos[i].SrcID;

                    DALOpr.ExecuteNonQuery(sql, ref msg);

                    //插入码明细
                    DataTable dt = new DataTable();
                    dt.Columns.Add("code", typeof(string));
                    dt.Columns.Add("PrintInfoID", typeof(int));

                    foreach (var item in printDatas[i])
                    {
                        DataRow dr = dt.NewRow();
                        dr[0] = item;
                        dr[1] = printerInfos[i].SrcID;

                        dt.Rows.Add(dr);
                    }

                    DALOpr.ExcuteBulkCopy("PrintCode", dt, ref msg);

                }
                printerInfos.Clear();
                printDatas.Clear();
            }

        }

        public bool IfTaskFree()
        {
            if (PublicObject.CurTask != null && PublicObject.CurTask.state != (int)task_state.TS_NEW)
            {
                return false;
            }

            return true;
        }

        #endregion

        public void RefreshCodeQty()
        {
            if (CodeRefreshEvent != null)
            {
                CodeRefreshEvent(this, null);
            }
        }

        public package_state GetCurrentTaskPS()
        {
            if (CodePrcUtility.GetUnpackQty() > 0)
            {
                return package_state.PS_UNBOX;
            }

            if (CodePrcUtility.GetZeroQty() > 0)
            {
                return package_state.PS_ZERO;
            }

            return package_state.PS_NORMAL;
        }

        #region 关于打印

        public string GetPrintInfoString()
        {
            StringBuilder sb = new StringBuilder();

            for (int i = 0; i < printDatas.Count; i++)
            {
                sb.Append(string.Format("[{0}级]{1} ", printerInfos[i].StationNum, printDatas[i].Count));
            }

            return sb.ToString();
        }
        public void Test()
        {
            //测试
            if (CriticalErrorEvent != null)
            {
                ErrorString = string.Format("{0}号工位待打印数据已不足{1}条，剩余{2}条", 3, nPrintLackQty, 10);
                CriticalErrorEvent(this, new EventArgs());
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pi">打印信息</param>
        /// <param name="code">条码内容</param>
        /// <param name="sn">序列号</param>
        /// <param name="msg"></param>
        /// <param name="bSaveCode">是否保存打印数据</param>
        /// <returns></returns>
        bool Print(ProductionTask task, PrintInfo pin, string code, int sn, bool bSaveCode, ref string msg)
        {

#if USE_BARTENDER
            PrintAction pai = new PrintAction();
            pai.Code = code;
            pai.PI = pin;
            pai.SN = sn;
            pai.Task = task;
            pai.BSaveCode = bSaveCode;

            try
            {
                return ThreadPool.QueueUserWorkItem(new WaitCallback((s) =>
                {
                    PrintAction act = (PrintAction)s;

                    LabelFormatDocument lfd = null;
                    string msgAct = "";

                    while (engine.IsPrinting)
                    {
                        Thread.Sleep(100);
                    }

                    try
                    {
                        lfd = engine.Documents.Open(act.PI.TemplatePath);
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("打开打印模板失败：" + exp.Message);
                        msgAct = "打开打印模板失败：" + exp.Message;
                    }


                    try
                    {
                        lfd.SubStrings.SetSubString("code", act.Code);
                    }
                    catch (Exception exp)
                    {

                        Console.WriteLine("写入Substring出现错误：" + exp.Message);
                        msgAct = "写入Substring出现错误：" + exp.Message;
                    }


                    try
                    {
                        lfd.SubStrings.SetSubString("product", act.Task.tym);
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("写入Substring出现错误：" + exp.Message);
                    }

                    try
                    {
                        lfd.SubStrings.SetSubString("sn", act.SN.ToString());
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("写入Substring出现错误：" + exp.Message);
                    }


                    try
                    {
                        lfd.SubStrings.SetSubString("spm", act.Task.spm);
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("写入Substring出现错误：" + exp.Message);
                    }

                    try
                    {
                        lfd.SubStrings.SetSubString("pzwh", act.Task.pzwh);
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("写入Substring出现错误：" + exp.Message);
                    }

                    try
                    {
                        lfd.SubStrings.SetSubString("specification", act.Task.gg);
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("写入Substring出现错误：" + exp.Message);
                    }

                    try
                    {
                        lfd.SubStrings.SetSubString("batchNo", act.Task.batch);
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("写入Substring出现错误：" + exp.Message);
                    }

                    try
                    {
                        lfd.SubStrings.SetSubString("produceDate", act.Task.produceDate.ToString("yyyy-MM-dd"));
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("写入Substring出现错误：" + exp.Message);
                    }

                    try
                    {
                        lfd.SubStrings.SetSubString("yxq", act.Task.yxq.ToString("yyyy-MM-dd"));
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("写入Substring出现错误：" + exp.Message);
                    }

                    if (string.IsNullOrEmpty(msgAct))
                    {
                        try
                        {
                            Messages messages;
                            lfd.PrintSetup.IdenticalCopiesOfLabel = act.PI.PrintQty;

                            while (engine.IsPrinting)
                            {
                                Thread.Sleep(200);
                            }
                            Result result = lfd.Print(act.Task.batch + "批次打印" + act.PI.StationNum + "级别码", out messages);//开始打印


                            msgAct = "";

                            foreach (Seagull.BarTender.Print.Message message in messages)
                            {
                                msgAct += "\n" + message.Text;
                            }

                            if (result == Result.Failure)
                            {
                                if (!msgAct.Contains("Printer Maestro"))
                                {
                                    ErrorString = string.Format("{0}号工位打印出错：{1}，打印条码={2}", act.PI.StationNum, msgAct, act.Code);
                                    CriticalErrorEvent(this, new EventArgs());
                                }

                            }
                            else
                            {
                                if (act.BSaveCode)
                                {
                                    CodePrintEvent(this, new CodePrintEventArg(act.PI, act.Code, "打印成功，24位条码内容=" + AppHelper.SYZSGet24BitFromCodeNoCheck(act.Code)));
                                }
                            }

                            if (act.BSaveCode)
                            {
                                //if (CodePrcUtility.SavePrintCode(act.Code, act.PI.StationNum, ref msgAct) == en_code_prc.CP_NORMAL)
                                //{
                                //    int idxPI = printerInfos.IndexOf(act.PI);
                                //    if (printDatas[idxPI].Count < nPrintLackQty)
                                //    {
                                //        if (CriticalErrorEvent != null)
                                //        {
                                //            ErrorString = string.Format("{0}号工位待打印数据已不足{1}条，剩余{2}条", act.PI.StationNum, nPrintLackQty, printDatas[idxPI].Count);
                                //            CriticalErrorEvent(this, new EventArgs());
                                //        }
                                //    }
                                //}
                                //else
                                //{
                                //    ErrorString = string.Format("{0}号工位打印数据保存出错：{1}，待保存数据={2}", act.PI.StationNum, msgAct, act.Code);
                                //    CriticalErrorEvent(this, new EventArgs());
                                //}
                                LineDevice dev = GetPrinterByInfo(act.PI);

                                if (dev == null)
                                {
                                    ErrorString = string.Format("{0}号工位打印数据保存出错：无法获取到打印设备，待保存数据={1}", act.PI.StationNum, act.Code);
                                    CriticalErrorEvent(this, new EventArgs());
                                }
                                else
                                {
                                    InputDataPrc.GetInstance().PutInputData(dev, act.Code);

                                    int idxPI = printerInfos.IndexOf(act.PI);
                                    if (printDatas[idxPI].Count < nPrintLackQty)
                                    {
                                        if (CriticalErrorEvent != null)
                                        {
                                            ErrorString = string.Format("{0}号工位待打印数据已不足{1}条，剩余{2}条", act.PI.StationNum, nPrintLackQty, printDatas[idxPI].Count);
                                            CriticalErrorEvent(this, new EventArgs());
                                        }
                                    }

                                    if (CodePrintEvent != null)
                                    {
                                        CodePrintEvent(this, new CodePrintEventArg(act.PI, act.Code, "打印成功"));
                                    }
                                }

                            }
                        }
                        catch (Exception exp)
                        {
                            ErrorString = string.Format("{0}号工位打印出错：{1}，打印条码={2}", act.PI.StationNum, exp.Message, act.Code);
                            CriticalErrorEvent(this, new EventArgs());
                        }
                    }
                    else
                    {
                        ErrorString = string.Format("{0}号工位打印出错：{1}，打印条码={2}", act.PI.StationNum, msgAct, act.Code);
                        CriticalErrorEvent(this, new EventArgs());
                    }

                    try
                    {
                        lfd.Close(SaveOptions.DoNotSaveChanges);
                    }
                    catch (Exception)
                    {

                    }

                }), pai);
            }
            catch (Exception exp)
            {
                msg = exp.Message;
                return false;
            }

#else
            return true;
#endif




        }

        /// <summary>
        /// 打印测试，从任务数据中取一条数据重复打印
        /// </summary>
        /// <param name="t"></param>
        /// <param name="station">工位号</param>
        /// <param name="msg"></param>
        /// <param name="nCopy">重复打印数量</param>
        /// <returns></returns>
        public bool PrintTest(ProductionTask t, int station, int nCopy,  ref string msg)
        {     
#if USE_BARTENDER
                if (engine == null)
                {
                    engine = new Engine(true);
                }
#endif

            string sql = string.Format("select top 1 * from PrintInfo where taskid={0} and stationNum = {1}", t.ID, station);

            PrintInfo pi = DALOpr.QuerySingle<PrintInfo>(sql, ref msg);

            if (pi == null)
            {
                msg = "该生产任务" + station + "工位未配备打印机！";
                return false;
            }

            if (string.IsNullOrEmpty(pi.TemplatePath) || !File.Exists(pi.TemplatePath))
            {
                msg = "该生产任务" + station + "工位的打印模板不存在！";
                return false;
            }


            pi.PrintQty = nCopy;

            string code = "";
            if (File.Exists(pi.CodePath) && new FileInfo(pi.CodePath).Length>0)
            {
                code = File.ReadAllLines(pi.CodePath, FileUtil.GetEncoding(pi.CodePath))[0];

                return Print(t, pi, code, 0, false, ref msg);
            }
            else
            {
                

                sql = string.Format("select top 1 * from CodeInfo where taskid={0} and stationNumber = {1}", t.ID, station);

                CodeInfo ci = DALOpr.QuerySingle<CodeInfo>(sql, ref msg);
                code = string.Format("{0}，{1}，{2}，{3}，{4}", ci.code, t.tym, t.pzwh, PublicObject.CurCompany.name, PublicObject.CurCompany.phone);

                if (ci == null)
                {
                    msg = "生产任务内无可打印数据！";
                    return false;
                }

                return Print(t, pi, code, ci.serialNumber, false, ref msg);
            }
            
        }


        public bool RePrintOneLabel(string code, int nCopys, ref string msg)
        {
            CodeInfo ci = CodePrcUtility.FindCode(code);

            if (ci == null)
            {
                msg = "码不存在";
                return false;
            }
            foreach (var pi in printerInfos)
            {
                if (pi.StationNum == ci.stationNumber)
                {
                    string newCode = AppHelper.SYZSSet24Bit(printDatas[0][0], code);
                    int oldQty = pi.PrintQty;
                    pi.PrintQty = nCopys;
                    //bool b = Print(PublicObject.CurTask, pi, newCode, ci.serialNumber, false, ref msg);
                    bool b = Print(PublicObject.CurTask, pi, newCode, CodePrcUtility.FindCodePos(ci) + 1, false, ref msg);
                    pi.PrintQty = oldQty;

                    return b;
                }
            }

            msg = "缺少" + ci.stationNumber + "工位的打印机，无法打印";
            return false;

        }

        public bool PrintOneLabel(int station, ref string msg)
        {
            int idxPI;
            bool bRes = false;

            foreach (var pi in printerInfos)
            {
                if (pi.StationNum == station)
                {
                    idxPI = printerInfos.IndexOf(pi);
                    
                    string toPrint = string.Empty;

                    lock (objPrint)
                    {
                        while (printDatas[idxPI].Count > 0)
                        {
                            if (!CodePrcUtility.IfCodeCanPrint(printDatas[idxPI][0], station, ref msg))
                            {
                                Console.WriteLine("无法打印，移除重复数据：" + printDatas[idxPI][0]);
                                printDatas[idxPI].RemoveAt(0);
                            }
                            else
                            {
                                toPrint = printDatas[idxPI][0];
                                printDatas[idxPI].RemoveAt(0);
                                break;
                            }
                        }

                    }

                    if (!string.IsNullOrEmpty(toPrint))
                    {
                        bRes = Print(PublicObject.CurTask, pi, toPrint, CodePrcUtility.GetPrintSN(station), true, ref msg);

                        if (!bRes)
                        {
                            ErrorString = string.Format("{0}号工位打印出错：{1}，打印条码={2}", station, msg, toPrint);
                            CriticalErrorEvent(this, new EventArgs());
                        }
                    }
                    else
                    {
                        msg = "无数据可打印";
                    }

                    if (!bRes)
                    {
                        ErrorString = msg;
                        if (CriticalErrorEvent!=null)
                        {
                            CriticalErrorEvent(this, new EventArgs());
                        }
                    }
                    return bRes;
                }
            }

            msg = "缺少" + station + "工位的打印机，无法打印";

            if (!bRes)
            {
                ErrorString = msg;
                if (CriticalErrorEvent != null)
                {
                    CriticalErrorEvent(this, new EventArgs());
                }
            }

            return false;
        }

        /// <summary>
        /// 同时打印两个工位标签
        /// </summary>
        /// <param name="station1"></param>
        /// <param name="station2"></param>
        /// <param name="bSaveCode">是否保存要打印的数据</param>
        /// <param name="msg"></param>
        /// <returns></returns>
        public bool PrintTwoLabels(int station1, int station2, bool bSaveCode, ref string msg)
        {
            int idxPI;
            List<PrintAction> li = new List<PrintAction>();
            PrintAction pai;

            foreach (var pi in printerInfos)
            {
                if (pi.StationNum == station1)
                {
                    idxPI = printerInfos.IndexOf(pi);

                    string toPrint = string.Empty;

                    lock (objPrint)
                    {
                        while (printDatas[idxPI].Count > 0)
                        {
                            if (!CodePrcUtility.IfCodeCanPrint(printDatas[idxPI][0], station1, ref msg))
                            {
                                Console.WriteLine("无法打印，移除重复数据：" + printDatas[idxPI][0]);
                                printDatas[idxPI].RemoveAt(0);
                            }
                            else
                            {

                                pai = new PrintAction();
                                pai.Code = printDatas[idxPI][0];
                                pai.PI = pi;
                                pai.SN = CodePrcUtility.GetPrintSN(station1);
                                pai.Task = PublicObject.CurTask;
                                pai.BSaveCode = bSaveCode;

                                printDatas[idxPI].RemoveAt(0);
                                li.Add(pai);
                                break;
                            }
                        }

                    }


                }

                if (pi.StationNum == station2)
                {
                    idxPI = printerInfos.IndexOf(pi);

                    string toPrint = string.Empty;

                    lock (objPrint)
                    {
                        while (printDatas[idxPI].Count > 0)
                        {
                            if (!CodePrcUtility.IfCodeCanPrint(printDatas[idxPI][0], station2, ref msg))
                            {
                                Console.WriteLine("无法打印，移除重复数据：" + printDatas[idxPI][0]);
                                printDatas[idxPI].RemoveAt(0);
                            }
                            else
                            {
                                pai = new PrintAction();
                                pai.Code = printDatas[idxPI][0];
                                pai.PI = pi;
                                pai.SN = CodePrcUtility.GetPrintSN(station2);
                                pai.Task = PublicObject.CurTask;
                                pai.BSaveCode = bSaveCode;
                                printDatas[idxPI].RemoveAt(0);
                                li.Add(pai);
                                break;
                            }
                        }

                    }


                }
            }

            if (li.Count == 2 )
            {

#if USE_BARTENDER

                try
                {
                    return ThreadPool.QueueUserWorkItem(new WaitCallback((s) =>
                    {
                        List<PrintAction> acts = (List<PrintAction>)s;

                        LabelFormatDocument lfd = null;
                        string msgAct = "";

                        while(engine.IsPrinting)
                        {
                            Thread.Sleep(100);
                        }

                        foreach (var act in acts)
                        {
                            msgAct = string.Empty;

                            try
                            {
                                lfd = engine.Documents.Open(act.PI.TemplatePath);
                            }
                            catch (Exception exp)
                            {
                                Console.WriteLine("打开打印模板失败：" + exp.Message);
                                msgAct = "打开打印模板失败：" + exp.Message;

                                ErrorString = msgAct;
                                CriticalErrorEvent(this, new EventArgs());
                                return;
                            }

                            try
                            {
                                lfd.SubStrings.SetSubString("code", act.Code);
                            }
                            catch (Exception exp)
                            {

                                Console.WriteLine("写入Substring出现错误：" + exp.Message);
                                msgAct = "写入Substring出现错误：" + exp.Message;
                            }


                            try
                            {
                                lfd.SubStrings.SetSubString("product", act.Task.tym);
                            }
                            catch (Exception exp)
                            {
                                Console.WriteLine("写入Substring出现错误：" + exp.Message);
                            }

                            try
                            {
                                lfd.SubStrings.SetSubString("sn", act.SN.ToString());
                            }
                            catch (Exception exp)
                            {
                                Console.WriteLine("写入Substring出现错误：" + exp.Message);
                            }


                            try
                            {
                                lfd.SubStrings.SetSubString("spm", act.Task.spm);
                            }
                            catch (Exception exp)
                            {
                                Console.WriteLine("写入Substring出现错误：" + exp.Message);
                            }

                            try
                            {
                                lfd.SubStrings.SetSubString("pzwh", act.Task.pzwh);
                            }
                            catch (Exception exp)
                            {
                                Console.WriteLine("写入Substring出现错误：" + exp.Message);
                            }

                            try
                            {
                                lfd.SubStrings.SetSubString("specification", act.Task.gg);
                            }
                            catch (Exception exp)
                            {
                                Console.WriteLine("写入Substring出现错误：" + exp.Message);
                            }

                            try
                            {
                                lfd.SubStrings.SetSubString("batchNo", act.Task.batch);
                            }
                            catch (Exception exp)
                            {
                                Console.WriteLine("写入Substring出现错误：" + exp.Message);
                            }

                            try
                            {
                                lfd.SubStrings.SetSubString("produceDate", act.Task.produceDate.ToString("yyyy-MM-dd"));
                            }
                            catch (Exception exp)
                            {
                                Console.WriteLine("写入Substring出现错误：" + exp.Message);
                            }

                            try
                            {
                                lfd.SubStrings.SetSubString("yxq", act.Task.yxq.ToString("yyyy-MM-dd"));
                            }
                            catch (Exception exp)
                            {
                                Console.WriteLine("写入Substring出现错误：" + exp.Message);
                            }

                            if (string.IsNullOrEmpty(msgAct))
                            {
                                try
                                {
                                    Messages messages;
                                    lfd.PrintSetup.IdenticalCopiesOfLabel = act.PI.PrintQty;
                                    Result result = lfd.Print(act.Task.batch + "批次打印" + act.PI.StationNum + "级别码", System.Threading.Timeout.Infinite, out messages);//开始打印


                                    msgAct = "";

                                    foreach (Seagull.BarTender.Print.Message message in messages)
                                    {
                                        msgAct += "\n" + message.Text;
                                    }

                                    if (result == Result.Failure)
                                    {
                                        if (!msgAct.Contains("Printer Maestro"))
                                        {
                                            ErrorString = string.Format("{0}号工位打印出错：{1}，打印条码={2}", act.PI.StationNum, msgAct, act.Code);
                                            CriticalErrorEvent(this, new EventArgs());
                                        }

                                    }
                                    else
                                    {
                                        if (act.BSaveCode)
                                        {
                                            CodePrintEvent(this, new CodePrintEventArg(act.PI, act.Code, "打印成功，24位条码内容=" + AppHelper.SYZSGet24BitFromCodeNoCheck(act.Code)));
                                        }
                                    }



                                    if (act.BSaveCode)
                                    {
                                        LineDevice dev = GetPrinterByInfo(act.PI);

                                        if (dev == null)
                                        {
                                            ErrorString = string.Format("{0}号工位打印数据保存出错：无法获取到打印设备，待保存数据={1}", act.PI.StationNum, act.Code);
                                            CriticalErrorEvent(this, new EventArgs());
                                        }
                                        else
                                        {
                                            InputDataPrc.GetInstance().PutInputData(dev, act.Code);

                                            int idx = printerInfos.IndexOf(act.PI);
                                            if (printDatas[idx].Count < nPrintLackQty)
                                            {
                                                if (CriticalErrorEvent != null)
                                                {
                                                    ErrorString = string.Format("{0}号工位待打印数据已不足{1}条，剩余{2}条", act.PI.StationNum, nPrintLackQty, printDatas[idx].Count);
                                                    CriticalErrorEvent(this, new EventArgs());
                                                }
                                            }

                                            if (CodePrintEvent != null)
                                            {
                                                CodePrintEvent(this, new CodePrintEventArg(act.PI, act.Code, "打印成功"));
                                            }
                                        }

                                    }

                                }
                                catch (Exception exp)
                                {
                                    ErrorString = string.Format("{0}号工位打印出错：{1}，打印条码={2}", act.PI.StationNum, exp.Message, act.Code);
                                    CriticalErrorEvent(this, new EventArgs());
                                }
                            }
                            else
                            {
                                ErrorString = string.Format("{0}号工位初始化打印信息出错：{1}，打印条码={2}", act.PI.StationNum, msgAct, act.Code);
                                CriticalErrorEvent(this, new EventArgs());
                            }

                            try
                            {
                                lfd.Close(SaveOptions.DoNotSaveChanges);

                                //再延时1秒 2020-12-24,放置连续打印冲突
                                Thread.Sleep(1000);
                            }
                            catch (Exception)
                            {

                            }
                        }

                        

                    }), li);
                }
                catch (Exception exp)
                {
                    msg = exp.Message;
                    return false;
                }

#else
            return true;
#endif
            }
            else
            {
                if (li.Count == 1)
                {
                    msg = "只有工位"+li[0].PI.StationNum+"数据可打印";
                }
                else
                {
                    msg = " 两个工位均无数据可打印";
                }


                ErrorString = msg;
                if (CriticalErrorEvent != null)
                {
                    CriticalErrorEvent(this, new EventArgs());
                }

                return false;
            }

        }


        public bool PrintLabels(int station, int nQty, ref string msg)
        {
            int idxPI;
            bool bRes = false;

            foreach (var pi in printerInfos)
            {
                if (pi.StationNum == station)
                {
                    idxPI = printerInfos.IndexOf(pi);

                    List<string> toPrint = new List<string>();

                    lock (objPrint)
                    {
                        while (printDatas[idxPI].Count > 0)
                        {
                            if (!CodePrcUtility.IfCodeCanPrint(printDatas[idxPI][0], station, ref msg))
                            {
                                Console.WriteLine("无法打印，移除重复数据：" + printDatas[idxPI][0]);
                                printDatas[idxPI].RemoveAt(0);
                            }
                            else
                            {
                                toPrint.Add(printDatas[idxPI][0]);
                                printDatas[idxPI].RemoveAt(0);

                                if (toPrint.Count == nQty)
                                {
                                    break;
                                }
                                
                            }
                        }

                    }

                    if (toPrint.Count == nQty)
                    {
                        bRes = Print(PublicObject.CurTask, pi, toPrint, CodePrcUtility.GetPrintSN(station), true, ref msg);

                        if (!bRes)
                        {
                            ErrorString = string.Format("{0}号工位打印出错：{1}，打印条码={2}", station, msg, toPrint);
                            CriticalErrorEvent(this, new EventArgs());
                        }
                    }
                    else
                    {
                        msg = "数据量不够打印，仅剩数据" + toPrint.Count + "条";
                        printDatas[idxPI].AddRange(toPrint);//数据放回去
                    }

                    if (!bRes)
                    {
                        ErrorString = msg;
                        if (CriticalErrorEvent != null)
                        {
                            CriticalErrorEvent(this, new EventArgs());
                        }
                    }
                    return bRes;
                }
            }

            msg = "缺少" + station + "工位的打印机，无法打印";

            if (!bRes)
            {
                ErrorString = msg;
                if (CriticalErrorEvent != null)
                {
                    CriticalErrorEvent(this, new EventArgs());
                }
            }

            return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="pi">打印信息</param>
        /// <param name="code">条码内容</param>
        /// <param name="sn">序列号</param>
        /// <param name="msg"></param>
        /// <param name="bSaveCode">是否保存打印数据</param>
        /// <returns></returns>
        bool Print(ProductionTask task, PrintInfo pin, List<string> codes, int sn, bool bSaveCode, ref string msg)
        {

#if USE_BARTENDER
            PrintAction pai = new PrintAction();
            pai.Code = codes.Aggregate((s1,s2)=>s1+","+s2);
            pai.PI = pin;
            pai.SN = sn;
            pai.Task = task;
            pai.BSaveCode = bSaveCode;

            try
            {
                return ThreadPool.QueueUserWorkItem(new WaitCallback((s) =>
                {
                    PrintAction act = (PrintAction)s;

                    LabelFormatDocument lfd = null;
                    string msgAct = "";


                    string[] arrCodes = act.Code.Split(new char[]{ ','});

                    while (engine.IsPrinting)
                    {
                        Thread.Sleep(100);
                    }

                    try
                    {
                        lfd = engine.Documents.Open(act.PI.TemplatePath);
                    }
                    catch (Exception exp)
                    {
                        Console.WriteLine("打开打印模板失败：" + exp.Message);
                        msgAct = "打开打印模板失败：" + exp.Message;

                        ErrorString = msgAct;
                        CriticalErrorEvent(this, new EventArgs());
                        return;
                    }

                    foreach (var code in arrCodes)
                    {
                        msgAct = string.Empty;

                        try
                        {
                            lfd.SubStrings.SetSubString("code", code);
                        }
                        catch (Exception exp)
                        {

                            Console.WriteLine("写入Substring出现错误：" + exp.Message);
                            msgAct = "写入Substring出现错误：" + exp.Message;
                        }

                        try
                        {
                            lfd.SubStrings.SetSubString("product", act.Task.tym);
                        }
                        catch (Exception exp)
                        {
                            Console.WriteLine("写入Substring出现错误：" + exp.Message);
                        }

                        try
                        {
                            lfd.SubStrings.SetSubString("sn", act.SN.ToString());
                            act.SN++;
                        }
                        catch (Exception exp)
                        {
                            Console.WriteLine("写入Substring出现错误：" + exp.Message);
                        }


                        try
                        {
                            lfd.SubStrings.SetSubString("spm", act.Task.spm);
                        }
                        catch (Exception exp)
                        {
                            Console.WriteLine("写入Substring出现错误：" + exp.Message);
                        }

                        try
                        {
                            lfd.SubStrings.SetSubString("pzwh", act.Task.pzwh);
                        }
                        catch (Exception exp)
                        {
                            Console.WriteLine("写入Substring出现错误：" + exp.Message);
                        }

                        try
                        {
                            lfd.SubStrings.SetSubString("specification", act.Task.gg);
                        }
                        catch (Exception exp)
                        {
                            Console.WriteLine("写入Substring出现错误：" + exp.Message);
                        }

                        try
                        {
                            lfd.SubStrings.SetSubString("batchNo", act.Task.batch);
                        }
                        catch (Exception exp)
                        {
                            Console.WriteLine("写入Substring出现错误：" + exp.Message);
                        }

                        try
                        {
                            lfd.SubStrings.SetSubString("produceDate", act.Task.produceDate.ToString("yyyy-MM-dd"));
                        }
                        catch (Exception exp)
                        {
                            Console.WriteLine("写入Substring出现错误：" + exp.Message);
                        }

                        try
                        {
                            lfd.SubStrings.SetSubString("yxq", act.Task.yxq.ToString("yyyy-MM-dd"));
                        }
                        catch (Exception exp)
                        {
                            Console.WriteLine("写入Substring出现错误：" + exp.Message);
                        }

                        if (string.IsNullOrEmpty(msgAct))
                        {
                            try
                            {
                                Messages messages;
                                lfd.PrintSetup.IdenticalCopiesOfLabel = act.PI.PrintQty;
                                Result result = lfd.Print(act.Task.batch + "批次打印" + act.PI.StationNum + "级别码", System.Threading.Timeout.Infinite, out messages);//开始打印


                                msgAct = "";

                                foreach (Seagull.BarTender.Print.Message message in messages)
                                {
                                    msgAct += "\n" + message.Text;
                                }

                                if (result == Result.Failure)
                                {
                                    if (!msgAct.Contains("Printer Maestro"))
                                    {
                                        ErrorString = string.Format("{0}号工位打印失败：{1}，打印条码={2}", act.PI.StationNum, msgAct, code);
                                        CriticalErrorEvent(this, new EventArgs());
                                    }

                                }
                                else
                                {
                                    if (act.BSaveCode)
                                    {
                                        CodePrintEvent(this, new CodePrintEventArg(act.PI, code, "打印成功，24位条码内容=" + AppHelper.SYZSGet24BitFromCodeNoCheck(code)));
                                    }
                                }

                                

                                if (act.BSaveCode)
                                {
                                    LineDevice dev = GetPrinterByInfo(act.PI);

                                    if (dev == null)
                                    {
                                        ErrorString = string.Format("{0}号工位打印数据保存出错：无法获取到打印设备，待保存数据={1}", act.PI.StationNum, code);
                                        CriticalErrorEvent(this, new EventArgs());
                                    }
                                    else
                                    {
                                        InputDataPrc.GetInstance().PutInputData(dev, code);

                                        int idxPI = printerInfos.IndexOf(act.PI);
                                        if (printDatas[idxPI].Count < nPrintLackQty)
                                        {
                                            if (CriticalErrorEvent != null)
                                            {
                                                ErrorString = string.Format("{0}号工位待打印数据已不足{1}条，剩余{2}条", act.PI.StationNum, nPrintLackQty, printDatas[idxPI].Count);
                                                CriticalErrorEvent(this, new EventArgs());
                                            }
                                        }

                                        if (CodePrintEvent != null)
                                        {
                                            CodePrintEvent(this, new CodePrintEventArg(act.PI, code, "打印成功"));
                                        }
                                    }

                                }
                            }
                            catch (Exception exp)
                            {
                                ErrorString = string.Format("{0}号工位打印异常：{1}，打印条码={2}", act.PI.StationNum, exp.Message, code);
                                CriticalErrorEvent(this, new EventArgs());
                            }
                        }
                        else
                        {
                            ErrorString = string.Format("{0}号工位无法打印：{1}，打印条码={2}", act.PI.StationNum, msgAct, code);
                            CriticalErrorEvent(this, new EventArgs());
                        }

                    }

                    try
                    {
                        lfd.Close(SaveOptions.DoNotSaveChanges);
                    }
                    catch (Exception)
                    {

                    }
                    

                }), pai);
            }
            catch (Exception exp)
            {
                msg = exp.Message;
                return false;
            }

#else
            return true;
#endif




        }

        public bool PrintZeroLabel(ref string msg)
        {
            if (printerInfos.Count==0)
            {
                msg = "缺少打印机，不能自动零箱";
                return false;
            }

            int tagLevel = PublicObject.CurTask.tagLevel;
            int[] ratios = AppHelper.GetLevelRatios(PublicObject.CurTask.tagRatio);
            int ratio32 = 0, ratio21 = 0, ratio43 = 0;
            bool bRes = true;

            switch (PublicObject.CurTask.tagLevel)
            {
                case 3:
                    ratio32 = ratios[0];
                    ratio21 = ratios[1];

                    break;
                case 4:
                    ratio43 = ratios[0];
                    ratio32 = ratios[1];
                    ratio21 = ratios[2];
                    break;
                default:
                    msg = "包装级别不支持：级别=" + tagLevel;
                    return false;

            }

            //先打印三级码
            bool b3 = false, b4 = false;
            foreach (var item in printerInfos)
            {
                if (item.StationNum == 3)
                {
                    int cnt = PublicObject.bSecond ? CodePrcUtility.GetScanTwiceQty() : PublicObject.arrCode2.Count;

                    if (PublicObject.arrCode3.Count*ratio32 < cnt)
                    {
                        //bRes &= PrintOneLabel(3, ref msg);
                        b3 = true;
                        //if (CodePrintEvent != null)
                        //{
                        //    CodePrintEvent(this, new CodePrintEventArg(item, PublicObject.arrCode3[PublicObject.arrCode3.Count - 1].code, "打印成功"));
                        //}

                        break;
                    }
                    else
                    {
                        msg = "二级码或二次扫描数量不足，无须打印三级零箱";
                        return false;
                    }
                }
            }

            //再打印四级码
            foreach (var item in printerInfos)
            {
                if (item.StationNum == 4)
                {
                    if (b3)
                    {
                        if (PublicObject.arrCode4.Count * ratio43 < (PublicObject.arrCode3.Count+1))
                        {
                            //bRes &= PrintOneLabel(4, ref msg);
                            b4 = true;
                            //if (CodePrintEvent != null)
                            //{
                            //    CodePrintEvent(this, new CodePrintEventArg(item, PublicObject.arrCode4[PublicObject.arrCode4.Count - 1].code, "打印成功"));
                            //}
                            break;
                        }
                        else
                        {
                            msg = "三级码数量不足，无须打印四级零箱";
                            return false;
                        }
                    }
                    else
                    {
                        if (PublicObject.arrCode4.Count * ratio43 < PublicObject.arrCode3.Count)
                        {
                            //bRes &= PrintOneLabel(4, ref msg);
                            b4 = true;
                            //if (CodePrintEvent != null)
                            //{
                            //    CodePrintEvent(this, new CodePrintEventArg(item, PublicObject.arrCode4[PublicObject.arrCode4.Count - 1].code, "打印成功"));
                            //}
                            break;
                        }
                        else
                        {
                            msg = "三级码数量不足，无须打印四级零箱";
                            return false;
                        }
                    }

                }
            }

            if (b3 && b4)
            {
                bRes = PrintTwoLabels(3, 4, true, ref msg);
            }
            else
            {
                if (b3)
                {
                    bRes = PrintOneLabel(3, ref msg);
                }

                if (b4)
                {
                    bRes = PrintOneLabel(4, ref msg);
                }
            }
            return bRes;
        }

        LineDevice GetPrinterByInfo(PrintInfo pi)
        {
            foreach (var item in devs)
            {
                if (item.stationNumber == pi.StationNum && item.IO == 1 && item.deviceType == (int)out_device_type.ODT_PRINTER && item.initString.Equals(pi.InitString, StringComparison.OrdinalIgnoreCase))
                {
                    return item;
                }
            }

            return null;
        }

        public bool ImportDataSource(string path, int station, ref string msg)
        {
            int idxPI = 0;
            IList<string> lines = File.ReadLines(path, Encoding.GetEncoding("GBK")).ToList();

            if (lines == null || lines.Count()<3)
            {
                msg = "文件过小，无法导入";
                return false;
            }

            if (!lines[1].Contains(PublicObject.CurProduct.tym) || !lines[1].Contains(PublicObject.CurProduct.pzwh))
            {
                msg = "产品名称或者批准文号与当前产品不一致";
                return false;
            }

            

            for (idxPI = 0; idxPI < printerInfos.Count; idxPI++)
            {
                PrintInfo pi = printerInfos[idxPI];

                if (pi.StationNum == station)
                {
                    pi.CodePath = path;

                    string sql = EntityHelper.GetUpdateSql(pi);
                    msg = string.Empty;

                    if (DALOpr.ExecuteNonQuery(sql, ref msg))
                    {
                        List<string> datas = File.ReadAllLines(path, FileUtil.GetEncoding(path)).ToList();

                        printDatas[idxPI].AddRange(datas);
                    }
                    else
                    {
                        return false;
                    }

                    return true;
                }
            }


            msg = "找不到该工位的打印信息";
            return false;
        }

        public void PutEditData(List<string> sa, exception_proccess ep)
        {
            InputDataPrc.GetInstance().PutEditData(sa, ep);
        }

        #endregion

        void sd_OnCode(LineDevice dev, string code)
        {
            string msg = string.Empty;
            int ratio = 1;

            code = code.Trim();

            if (dev.IO == (int)input_output.INPUT && dev.deviceType == (int)in_device_type.IDT_MANUAL_SCANER)
            {
                if (CodeScanEvent != null)
                {
                    string bit24 = AppHelper.SYZSGet24BitFromCodeNoCheck(code);
                    CodeScanEvent(this, new CodeScanEventArg(dev, bit24, code));
                }

                return;
            }

            InputDataPrc.GetInstance().PutInputData(dev, code);
        }
    }
}
